﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Text;
using System.IO;
using System.Net;
using System.Data.SqlClient;
using System.Data;

namespace sdamarketing.App_Code
{
    public class Analisys
    {
        //broj na pojavuvanja na termin do odreden dokument - Fi
        public int frekfencijaNaTerminVoDokument(String termin, String dokument)
        {
            int broj = 0;
            String[] pomDokument = dokument.Split(' ');
            for (int i = 0; i < pomDokument.Length; i++)
            {
                if (pomDokument[i].Contains(termin) && !termin.Equals(""))
                    broj++;
            }
            return broj;
        }

        //broj na dokumenti sto go sodrzat odreden termin - Di
        public int brDokumentiStoSodrzatTermin(String termin, String[] dokument)
        {
            int broj = 0;
            for (int i = 0; i < dokument.Length; i++)
            {
                if (dokument[i].Contains(termin))
                    broj++;
            }
            return broj;
        }

        //formula za dobivanje na element na matricata A
        //Fij-frekfencija na termin vo dokument, D-vkupen br. na dokumenti, Di-br. na dokumenti sto go sodrzat terminot
        public double elementNaA(int Fij, int D, int Di)
        {
            double rezultat;
            if (Math.Abs(Di) > 0)
                rezultat = Fij * Math.Round((Double)D / Di, 5);//Math.Round((Double)Math.Log10(D/Di), 5);
            else
                rezultat = 0;
            return rezultat;
        }

        //Evklidovi dolzini na vektorite, L2-normalizacija (se koristat za dobivanje na elementite na A(u))
        public double[] dolziniNaVektoriteNaA(double[][] matricaA)
        {
            double[] dolzini = new double[matricaA[0].Length];
            double suma = 0;
            for (int j = 0; j < matricaA[0].Length; j++)
            {
                for (int i = 0; i < matricaA.Length; i++)
                {
                    suma += Math.Pow(matricaA[i][j], 2);
                }
                dolzini[j] = Math.Round((Double)Math.Sqrt(suma), 5);
                suma = 0;
            }
            return dolzini;
        }

        //Evklidovi dolzini na vektorite, L2-normalizacija (se koristat za dobivanje na elementite na Q(u))
        public double dolzinaNaVektorotNaQ(double[] qVektor)
        {
            double dolzina;
            double suma = 0;
            for (int i = 0; i < qVektor.Length; i++)
            {
                suma += Math.Pow(qVektor[i], 2);
            }
            dolzina = Math.Round((Double)Math.Sqrt(suma), 5);
            return dolzina;
        }

        //kreiranje na query vektorot
        public double[] queryVektor(String[] termini, String query)
        {
            double[] qVektor = new double[termini.Length];

            for (int i = 0; i < qVektor.Length; i++)
            {
                if (query.ToUpper().Contains(termini[i]))
                    qVektor[i] = 1;
                else
                    qVektor[i] = 0;
            }
            return qVektor;
        }

        //kreiranje na vektorot q(u)
        public double[] queryVektorU(double[] qVektor)
        {
            double dolzinaNaVektor = dolzinaNaVektorotNaQ(qVektor);
            double[] pomVektor = new double[qVektor.Length];
            for (int i = 0; i < pomVektor.Length; i++)
            {
                pomVektor[i] = Math.Round((Double)qVektor[i] / dolzinaNaVektor, 5);
            }
            return pomVektor;
        }

        //kreiranje ma matricata A
        public double[][] matricaA(String[] termini, String[] dokumenti)
        {
            int frekfencija;
            int Di;
            int D = dokumenti.Length;
            double[][] matricaA = new double[termini.Length][];
            for (int i = 0; i < termini.Length; i++)
            {
                matricaA[i] = new double[dokumenti.Length];
                for (int j = 0; j < dokumenti.Length; j++)
                {
                    frekfencija = frekfencijaNaTerminVoDokument(termini[i], dokumenti[j]);
                    Di = brDokumentiStoSodrzatTermin(termini[i], dokumenti);
                    matricaA[i][j] = elementNaA(frekfencija, D, Di);
                }
            }
            return matricaA;
        }

        //kreiranje na matricata A(u)
        public double[][] matricaAu(double[][] matricaA)
        {
            double[] dolziniNaVektori = dolziniNaVektoriteNaA(matricaA);
            double[][] pomMatrica = new double[matricaA.Length][];

            for (int i = 0; i < matricaA.Length; i++)
            {
                pomMatrica[i] = new double[matricaA[0].Length];
                for (int j = 0; j < matricaA[0].Length; j++)
                {
                    pomMatrica[i][j] = Math.Round((Double)(matricaA[i][j] / dolziniNaVektori[j]), 5);
                }

            }
            return pomMatrica;
        }

        //mnozenje na matrici (q(u)*A(u))
        public double[] mnozenjeNaMatrici(double[] qVektorU, double[][] matricaAu)
        {
            double[] pomMatrica = new double[matricaAu[0].Length];
            for (int k = 0; k < matricaAu[0].Length; k++)
            {
                pomMatrica[k] = 0;
                for (int j = 0; j < matricaAu.Length; j++)
                {
                    pomMatrica[k] += Math.Round((Double)qVektorU[j] * matricaAu[j][k], 5);
                }
            }
            return pomMatrica;
        }

        //izvlekuvanjena isti termini od dokuentite
        public String[] getTermini(String[] dokumenti)
        {
            String[] pomDokument;
            String pomText = "";
            String[] rezultat;
            for (int i = 0; i < dokumenti.Length; i++)
            {

                dokumenti[i] = dokumenti[i].Replace(" AND ", " ");
                dokumenti[i] = dokumenti[i].Replace(" OR ", " ");
                dokumenti[i] = dokumenti[i].Replace(" OF ", " ");
                dokumenti[i] = dokumenti[i].Replace(" IN ", " ");
                dokumenti[i] = dokumenti[i].Replace(" BY ", " ");
                dokumenti[i] = dokumenti[i].Replace(" FOR ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ON ", " ");
                dokumenti[i] = dokumenti[i].Replace(" TO ", " ");
                dokumenti[i] = dokumenti[i].Replace(" THE ", " ");
                dokumenti[i] = dokumenti[i].Replace(" A ", " ");
                dokumenti[i] = dokumenti[i].Replace(" AN ", " ");
                dokumenti[i] = dokumenti[i].Replace(" AT ", " ");
                dokumenti[i] = dokumenti[i].Replace(" IS ", " ");
                dokumenti[i] = dokumenti[i].Replace(" IF ", " ");

                dokumenti[i] = dokumenti[i].Replace(" И ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ИЛИ ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ОД ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ВО ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ДО ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ЗА ", " ");
                dokumenti[i] = dokumenti[i].Replace(" НА ", " ");
                dokumenti[i] = dokumenti[i].Replace(" КОН ", " ");
                dokumenti[i] = dokumenti[i].Replace(" А ", " ");
                dokumenti[i] = dokumenti[i].Replace(" Е ", " ");
                dokumenti[i] = dokumenti[i].Replace(" У ", " ");
                dokumenti[i] = dokumenti[i].Replace(" В ", " ");
                dokumenti[i] = dokumenti[i].Replace(" ПОД ", " ");
                dokumenti[i] = dokumenti[i].Replace(" НАД ", " ");
                dokumenti[i] = dokumenti[i].Replace(" АКО ", " ");

                pomDokument = dokumenti[i].Split(' ', '.', ',', ':', ';', '?', '!', '@', '<', '>', '/', '(', ')', '-', '+', '_', '=', '#', '[', ']', '|', '"', '\'', '\\', '*', '$', '@', '{', '}');
                for (int j = 0; j < pomDokument.Length; j++)
                {
                    if (!pomText.Contains(pomDokument[j]) && !pomDokument[j].Equals(""))
                        pomText += pomDokument[j] + " ";
                }
            }

            String[] pom = pomText.Split(' ');
            rezultat = new String[pom.Length - 1];
            for (int i = 0; i < rezultat.Length; i++)
            {
                rezultat[i] = pom[i];
            }
            return rezultat;
        }

        //matrica vo koja 0-tata kolona e ID-to na korinikot a 1-vata kolona e textot
        public String[][] getDocsOdKorisnicite()
        {
            String[][] podatoci;
            DataSet dataSet = new DataSet();
            String sql = "SELECT idUser, textZaAnaliza FROM PodatociZaAnaliza";

            SqlConnection connection = ConnectionMenager.GetConnection();
            SqlCommand command = new SqlCommand(sql, connection);
            command.CommandType = CommandType.Text;

            SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
            dataAdapter.Fill(dataSet, "PodatociZaAnaliza");

            int redici = dataSet.Tables["PodatociZaAnaliza"].Rows.Count;
            podatoci = new String[redici][];

            for (int i = 0; i < redici; i++)
            {
                podatoci[i] = new String[2];

                podatoci[i][0] = dataSet.Tables["PodatociZaAnaliza"].Rows[i]["idUser"].ToString();
                podatoci[i][1] = (String)dataSet.Tables["PodatociZaAnaliza"].Rows[i]["textZaAnaliza"];
            }
            connection.Close();
            return podatoci;
        }

        //klucnite zborovi od reklamite
        public String[][] getKveriOdReklamite()
        {
            String[][] podatoci;
            DataSet dataSet = new DataSet();
            String sql = "SELECT idReklama, KlucniZborovi FROM PostavenaReklama WHERE Nacin = 1";

            SqlConnection connection = ConnectionMenager.GetConnection();
            SqlCommand command = new SqlCommand(sql, connection);
            command.CommandType = CommandType.Text;

            SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
            dataAdapter.Fill(dataSet, "PostavenaReklama");

            int redici = dataSet.Tables["PostavenaReklama"].Rows.Count;
            podatoci = new String[redici][];

            for (int i = 0; i < redici; i++)
            {
                podatoci[i] = new String[2];

                podatoci[i][0] = dataSet.Tables["PostavenaReklama"].Rows[i]["idReklama"].ToString();
                podatoci[i][1] = (String)dataSet.Tables["PostavenaReklama"].Rows[i]["KlucniZborovi"];
            }
            connection.Close();
            return podatoci;
        }


        public void analizaIZapisVoBaza()
        {
            int idBrojac = 1;

            String sql = "DELETE FROM ReklamiZaKorisnici";
            SqlConnection connection = ConnectionMenager.GetConnection();
            SqlCommand command = new SqlCommand(sql, connection);
            command.CommandType = CommandType.Text;
            command.ExecuteNonQuery();
            connection.Close();

            String[][] docs = getDocsOdKorisnicite();
            String[][] keywords = getKveriOdReklamite();

            String[] textoviZaAnaliza = new String[docs.Length]; //dokumenti za analiza od korisnicite
            String[] keywordsOdReklami = new String[keywords.Length]; //klucnite zborovi od reklamite

            int[] idUsers = new int[docs.Length]; //id's na korisnicite
            int[] idReklami = new int[keywords.Length]; //id's na reklamite

            for (int i = 0; i < docs.Length; i++)
            {
                idUsers[i] = int.Parse(docs[i][0]);
                textoviZaAnaliza[i] = docs[i][1].ToUpper();
            }
            for (int i = 0; i < keywords.Length; i++)
            {
                idReklami[i] = int.Parse(keywords[i][0]);
                keywordsOdReklami[i] = keywords[i][1].ToUpper();
            }

            String[] termini = getTermini(textoviZaAnaliza);
            double[][] matA = matricaA(termini, textoviZaAnaliza);

            //dolzini na vektorite na A
            double[] dolzinaVektoriA = dolziniNaVektoriteNaA(matA);
            //matricata A(u)
            double[][] matAu = matricaAu(matA);

            String query;
            //za sekoja reklama posebno kveri.. gi vrtam site reklami i vrednostite direkt vo baza
            for (int i = 0; i < keywordsOdReklami.Length; i++)
            {
                query = keywordsOdReklami[i].ToUpper();
                double[] vektor = queryVektor(termini, query);
                //dolzina na vektor na Q
                double dolzinaVektorQ = dolzinaNaVektorotNaQ(vektor);
                //vektorot q(u)
                double[] vektorU = queryVektorU(vektor);
                //rezultatot t.e. vrednostite na dokumentite od interes - nesortirani
                double[] rezultat = mnozenjeNaMatrici(vektorU, matAu);

                // bubble sort--------
                int x = rezultat.Length;
                double tempRezValue;
                int tempUserId;

                for (int ii = (x - 1); ii >= 0; ii--)
                {
                    for (int jj = 1; jj <= ii; jj++)
                    {
                        if (rezultat[jj - 1] > rezultat[jj])
                        {
                            tempRezValue = rezultat[jj - 1];
                            rezultat[jj - 1] = rezultat[jj];
                            rezultat[jj] = tempRezValue;
                            //--
                            tempUserId = idUsers[jj - 1];
                            idUsers[jj - 1] = idUsers[jj];
                            idUsers[jj] = tempUserId;
                        }
                    }
                }//end bubble

                //postravuvanje vo bazata -- se zemaat do predvid samo dokumentite t.e korisnicite so koeficient >0


                for (int k = rezultat.Length - 1; k >= 0; k--)
                {
                    if (rezultat[k] > 0)
                    {
                        connection = ConnectionMenager.GetConnection();

                        sql = "INSERT INTO ReklamiZaKorisnici (idRZK, idReklama, idUser, rezultat) VALUES ('" + idBrojac + "', '" + idReklami[i] + "', '" + idUsers[k] + "', '" + rezultat[k].ToString() + "')";
                        idBrojac++;
                        SqlCommand command2 = new SqlCommand(sql, connection);
                        command2.CommandType = CommandType.Text;
                        command2.ExecuteNonQuery();
                        connection.Close();
                    }
                }

            }//end glavniot FOR za vrtenje na reklamite

            zapisSopredParametri(idBrojac);

        }

        //raspredelba na reklamite spored dadeni parametri 
        //idReklama, Lokacija, Pol, VozrastOd, VozrastDo
        public void zapisSopredParametri(int counter)
        {
            SqlConnection connection = ConnectionMenager.GetConnection();
            reklamaEditor re = new reklamaEditor();
            DataSet reklami = re.getAllParametarskiReklami();
            int idReklama, VozrastOd, VozrastDo;
            String Lokacija, Pol;
            String sql = "";
            DataSet korisnici;

            for (int i = 0; i < reklami.Tables[0].Rows.Count; i++)
            {
                idReklama = Int32.Parse(reklami.Tables[0].Rows[i]["idReklama"].ToString());
                Lokacija = reklami.Tables[0].Rows[i]["Lokacija"].ToString();
                Pol = reklami.Tables[0].Rows[i]["Pol"].ToString();
                VozrastOd = Int32.Parse(reklami.Tables[0].Rows[i]["VozrastOd"].ToString());
                VozrastDo = Int32.Parse(reklami.Tables[0].Rows[i]["VozrastDo"].ToString());

                if (Lokacija.Equals("Сите градови"))
                {
                    if (Pol.Equals("Не е важен"))
                    {
                        korisnici = ReturnDataSet.ReturSet("SELECT idUser FROM Users, Age WHERE Age.idAge = Users.idAge AND Age.fromAge >= '" + VozrastOd + "' AND Age.toAge <= '" + VozrastDo + "'");
                    }
                    else
                    {
                        korisnici = ReturnDataSet.ReturSet("SELECT idUser FROM Users, Age, Sex WHERE Age.idAge = Users.idAge AND Sex.idSex = Users.idSex AND Age.fromAge >= '" + VozrastOd + "' AND Age.toAge <= '" + VozrastDo + "' AND Sex.sex = '" + Pol + "'");
                    }
                }
                else
                    // da dopravam po parametar grad koga ke se osposobi bazata!!!!!!!!!!!!!!!!!!!!!!!!!!
                {
                    if (Pol.Equals("Не е важен"))
                    {
                        korisnici = ReturnDataSet.ReturSet("SELECT idUser FROM Users,Regions, Age WHERE Age.idAge = Users.idAge AND Age.fromAge >= '" + VozrastOd + "' AND Age.toAge <= '" + VozrastDo + "' AND Users.idRegion = Regions.idRegion AND Regions.region = '" + Lokacija + "'");
                    }
                    else
                    {
                        korisnici = ReturnDataSet.ReturSet("SELECT idUser FROM Users,Regions, Age, Sex WHERE Age.idAge = Users.idAge AND Sex.idSex = Users.idSex AND Age.fromAge >= '" + VozrastOd + "' AND Age.toAge <= '" + VozrastDo + "' AND Sex.sex = '" + Pol + "' AND Users.idRegion = Regions.idRegion AND Regions.region = '" + Lokacija + "'");
                    }
                }

                for (int j = 0; j < korisnici.Tables[0].Rows.Count; j++)
                {
                    int idUser = Int32.Parse(korisnici.Tables[0].Rows[0][0].ToString());
                    connection = ConnectionMenager.GetConnection();
                    counter++;
                    sql = "INSERT INTO ReklamiZaKorisnici (idRZK, idReklama, idUser, rezultat) VALUES ('" + counter + "', '" + idReklama + "', '" + idUser + "', '" + 1 + "')";
                    SqlCommand command2 = new SqlCommand(sql, connection);
                    command2.CommandType = CommandType.Text;
                    command2.ExecuteNonQuery();
                    connection.Close();
                }

            }//kraj na for za reklamite
        }


    }
}